import { Context, h, Schema } from 'koishi'
import dayjs from 'dayjs'
import { lunarToSolar } from 'chinese-lunar'
import cron, {ScheduledTask} from 'node-cron'

import {} from 'koishi-plugin-adapter-onebot';

export const name = 'holiday-groupname'

export interface Holiday{
  name: string;
  type: 'solar' | 'lunar';
  month: number;
  day: number;
}

export interface Config {

  holidayList: Holiday[];

  enableHolidayCommand: boolean;
  enableShichenCommand: boolean;

  guildNamePrefix: string;
  guildId: string;
  dateFormateStr: string;

}

export const Config: Schema<Config> = Schema.intersect([

  Schema.object({
    holidayList: Schema.array(
      Schema.object({
        name: Schema.string()
          .required()
          .description("节日名称"),
        type: Schema.union(['solar', 'lunar'])
          .required()
          .description("公历or农历？"),
        month: Schema.number()
          .min(1).max(12)
          .required()
          .description("月份"),
        day: Schema.number()
          .min(1).max(31)
          .required()
          .description("日期")
      })
    )
      .role('table')
      .default([
        { name: "元旦",   type: "solar", month: 1, day: 1 },
        { name: "春节",   type: "lunar", month: 1, day: 1 }, // 农历正月初一
        { name: "清明节", type: "solar", month: 4, day: 4 },
        { name: "劳动节", type: "solar", month: 5, day: 1 },
        { name: "端午节", type: "lunar", month: 5, day: 5 }, // 农历五月初五
        { name: "中秋节", type: "lunar", month: 8, day: 15 }, // 农历八月十五
        { name: "国庆节", type: "solar", month: 10, day: 1 }
      ])
      .description("节日列表，用于设置群名片中的节日提醒。")

  }).description("节日设置"),

  Schema.object({
    enableHolidayCommand: Schema.boolean()
      .default(false)
      .description("是否开启节日指令"),
    enableShichenCommand: Schema.boolean()
      .default(false)
      .description("是否开启时辰指令")
  }).description("指令设置"),

  Schema.object({
    guildNamePrefix: Schema.string()
      .default("默认前缀-")
      .description("群名前缀"),
    guildId: Schema.string()
      .default("958366323")
      .description("群号"),
    dateFormateStr: Schema.string()
      .default("YYYY年MM月DD日")
      .description("日期的时间格式")
  }).description("改群名定时任务设置")
  
])

interface HolidayWithDate extends Holiday {
  date: dayjs.Dayjs;
  day_left: number;
}


// 计算一定时间范围内的节日
function getNearestHolidays(
  today: Date,
  config: Config,
  lower: number = 365,
  upper: number = 365
): HolidayWithDate[] {
  const todayDayjs = dayjs(today)
  const thisYear = todayDayjs.year()
  const nextYear = thisYear + 1

  const expandedHolidays: HolidayWithDate[] = []

  for (const holiday of config.holidayList) {
    const startYear = todayDayjs.subtract(lower, 'day').year()
    const endYear = todayDayjs.add(upper, 'day').year()

    for (let year = startYear; year <= endYear; year++) {
      let date: dayjs.Dayjs
      if (holiday.type === 'solar') {
        date = dayjs(`${year}-${holiday.month}-${holiday.day}`, 'YYYY-M-D')
      } else {
        const solarDate = lunarToSolar({ year, month: holiday.month, day: holiday.day, leap: false })
        date = dayjs(`${solarDate.year}-${solarDate.month}-${solarDate.day}`, 'YYYY-M-D')
      }

      const day_left = date.diff(todayDayjs, 'day')
      if (day_left >= -lower && day_left <= upper) {
        expandedHolidays.push({ ...holiday, date, day_left })
      }
    }
  }

  return expandedHolidays.sort((a, b) => a.day_left - b.day_left)
}

function getHolidaysStr(config: Config, lower: number = 365, upper: number = 365) {
  const today = new Date()
  const holidays = getNearestHolidays(today, config, lower, upper)

  let res = "";
  res += `今天是 ${dayjs(today).format('YYYY-MM-DD')}\n`
  res += `在[-${lower}, +${upper}] 天范围内的节日：\n`
  for (const h of holidays) {
    res += 
      `- ${h.name} \t（公历${h.date.format('YYYY年MM月DD日')}) `
      + `\n\t ${h.day_left >= 0 ? '还有' : '已经过去'} ${Math.abs(h.day_left)} 天\n`
  }
  return res;
}

  const CHINESE_HOUR = [
    '子时', // 23:00 - 01:00
    '丑时', // 01:00 - 03:00
    '寅时', // 03:00 - 05:00
    '卯时', // 05:00 - 07:00
    '辰时', // 07:00 - 09:00
    '巳时', // 09:00 - 11:00
    '午时', // 11:00 - 13:00
    '未时', // 13:00 - 15:00
    '申时', // 15:00 - 17:00
    '酉时', // 17:00 - 19:00
    '戌时', // 19:00 - 21:00
    '亥时', // 21:00 - 23:00
  ]

function getChineseTimeString(date, formatStr) {
  const hour = date.getHours()

  // 将小时映射到对应的时辰（0~23 -> 0~11）
  const index = Math.floor((hour + 1) % 24 / 2)
  const shichen = CHINESE_HOUR[index] //时辰

  const formatted = dayjs(date)
    // .format('YYYY年MM月DD日')
    .format(formatStr)
  return `${shichen}-${formatted}`
}

export function apply(ctx: Context, config: Config) {

  if ( config.enableHolidayCommand )
    ctx.command('ah')
      .alias("awa_holiday")
      .alias("节日")
      .alias("假期")
      .action( async ( { session, options } ) => { 
        let msg = `[awa_holiday]\n`;
        msg += getHolidaysStr(config) ;
        await session.send( h.quote(session.messageId) + msg );
      } )
  
  if ( config.enableShichenCommand )
    ctx.command('asc')
      .alias("awa_shichen")
      .alias("时辰")
      .action( async ( { session, options } ) => {
        let msg = `[awa_shichen]\n`;
        msg += getChineseTimeString( new Date(), config.dateFormateStr );
        await session.send( h.quote(session.messageId) + msg );

        await changeGroupNameTaskFunc();
      } )

  const changeGroupNameTaskFunc = async () => {
    ctx.logger.info(`[改带时间群名函数] ${new Date()} changeGroupNameTaskFunc 被调用了。`);
    const onebotBot = ctx.bots.find(bot => bot.platform === 'onebot');

    await onebotBot.internal._request(
      "set_group_name",
      {
        "group_id": config.guildId,
        "group_name": config.guildNamePrefix + getChineseTimeString( new Date(), config.dateFormateStr )
      }
    )
  }

  const jobs: ScheduledTask[] = [];

  const cronChangeGroupNameTaskJob = cron.schedule(
    '2 0 * * * *', 
    // '*/5 * * * * *',
    changeGroupNameTaskFunc
  );
  jobs.push(cronChangeGroupNameTaskJob);

  ctx.on('dispose', () => {
    ctx.logger.info('节日时辰群名 plugin disposed.')
    for (const job of jobs) {
      ctx.logger.info(`插件dispose，停止任务${job.name}`)
      job.stop();
    }
  });


}


